package tss.serverGui;

import java.io.*;
import javax.swing.*;
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
import javax.imageio.ImageIO;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.String;
import java.util.HashMap;
import java.util.Map;
import java.util.TimeZone;
import java.util.Locale;
import java.util.Calendar;
import java.lang.Math;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.text.NumberFormat;

import tss.common.ExtensionStates;
import tss.server.*;

public class SwitchCenter extends JFrame {
	//needed GUI variables
	private JFrame frame;

	//Output screen for debugging
	private JScrollPane screenPanel;
	private JTextArea outputScreen;

	//Jlabe to display names
	private JPanel titlePanel;
	private JPanel picPanel;
	private JPanel bottomPanel;
	private JLabel title;
	private JLabel pic;

	//Display Timne
	private JPanel timePanel;
	private JTextField timeDisplay;

	//Setup buttons 
	private JPanel drawPanel;
	private JPanel leftButtonPanel;
	private JPanel rightButtonPanel;

	//setup drawing area
	private DrawArea drawing;

	//setup timer to check every few seconds
	private Timer myTimer;

	//setup interface
	private ServerInterface server;
	
	private JButton[] buttons;

	public SwitchCenter(ServerInterface server) throws UnknownHostException {
		//local host info
		InetAddress addr = InetAddress.getLocalHost();
		
		//take out later use for mock
		//server = new Linker();
		this.server = server;

		//initialize frame
		frame = new JFrame("SwitchCenter Application -- Listening on: "+ addr.getHostAddress());
		frame.getContentPane().setLayout(new BorderLayout());
		frame.getContentPane().setSize(750,250);

		//initalize output screen
		screenPanel = new JScrollPane();
		outputScreen = new JTextArea();

		//initialize label
		titlePanel = new JPanel();
		picPanel = new JPanel();
		bottomPanel = new JPanel();
		title = new JLabel("Seng 401 - Switch Center - Developed by: Eric Bouwsema, Feras Rafih, Nicolas Roldan, Faizan Sajwani, Nadir Souraya, Scott Smith, Dalton Vu");
		
		//initialize display time
		timePanel = new JPanel();
		timeDisplay = new JTextField(5);

		//initialize button area for drawing
		drawPanel = new JPanel();
		leftButtonPanel = new JPanel();
		rightButtonPanel = new JPanel();
		drawPanel.setLayout(new BorderLayout());

		//initialize buttons
		this.buttons = new JButton[16];
		
		for(int i=0; i<buttons.length; i++)
		{
			buttons[i] = new JButton("Phone #"+(i+1));
		}
		
		//initailizng drawing area
		drawing = new DrawArea();

		//put output screen on frame
		outputScreen.setEditable(false);
		outputScreen.setRows(20);
		outputScreen.setColumns(40);
		screenPanel.setViewportView(outputScreen);
		frame.getContentPane().add(screenPanel, "West");

		//put label in frame
		BufferedImage myPicture = null;
		try{
			myPicture = ImageIO.read(new File("src//tss//resources//engg.jpg"));
		}catch(Exception e){
			e.getStackTrace();
		}
		if(myPicture == null)
			System.out.println("No picture found");

		pic = new JLabel(new ImageIcon(myPicture));

		picPanel.add(title);
		titlePanel.add(pic);
		bottomPanel.add(titlePanel, "North");
		bottomPanel.add(picPanel, "South");
		frame.getContentPane().add(bottomPanel, "South");

		//put display time screen on frame		
		timeDisplay.setEditable(false);
		timeDisplay.setBackground(Color.black);
		timeDisplay.setForeground(Color.green);
		timePanel.add(timeDisplay);
		frame.getContentPane().add(timePanel, "North");
		
		//put buttons on frame  and draw them
		leftButtonPanel.setLayout(new GridLayout(8,1));
		for(int i=0; i<8; i++)
		{
			leftButtonPanel.add(buttons[i]);
		}
	
		rightButtonPanel.setLayout(new GridLayout(8,1));
		for(int i=8; i<16; i++)
		{
			rightButtonPanel.add(buttons[i]);
		}
		
		drawPanel.add(leftButtonPanel, "West");
		drawPanel.add(rightButtonPanel, "East");

		//setup drawing area
		drawing.setBackground(Color.lightGray);
		drawPanel.add(drawing, "Center");
		frame.getContentPane().add(drawPanel, "East");

		//setup timer 
		myTimer = new Timer(100, new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				timerAction();
			}
		});

		//launch frame
		this.launchFrame();

		//start timer
		myTimer.start();
	}

	//runs every 0.1 seconds for updates
	public void timerAction() 
	{
		//update timer
		this.updateTime();

		//append messages to screen
		String x = server.getMessages();
		if (x != null && x != "")
			this.updateOutput(x);

		//get connections from server
		RouteDetail [] routes = server.getConnections();
		
		//get extension states
		ExtensionStates[] states = server.getExtensionStates();
		for(int i=0; i<buttons.length; i++)
		{
			if(states[i] == ExtensionStates.Available)
			{
				buttons[i].setBackground(Color.GREEN);
				buttons[i].setOpaque(true);
			}
			else if(states[i] == ExtensionStates.Busy)
			{
				buttons[i].setBackground(Color.YELLOW);
				buttons[i].setOpaque(true);
			}
			else
			{
				buttons[i].setBackground(Color.RED);
				buttons[i].setOpaque(true);
			}
		}
		
		for(int i = 0; i < routes.length; i++) 
		{
			if (routes[i] != null) 
			{
				int phone1 = routes[i].getExtensionA();
				int phone2 = routes[i].getExtensionB();
				this.showConnection(i+1,phone1,phone2);
			}
			else
			{
				this.hideConnection(i+1);
			}
		}
	}

	private void hideConnection(int trunk) {
		drawMainLine(trunk,0,0,0,0);
		drawBackLine(trunk,0,0,0,0);
		drawing.repaint();
	}

	public void updateTime() {
		//create new calendar object to get time
		TimeZone time;
		Locale location;
		Calendar cal;

		NumberFormat nf;

		location = new Locale("en", "CA");
		time = TimeZone.getTimeZone("Canada/Mountain");
		cal = Calendar.getInstance(time, location);

		nf = NumberFormat.getInstance();
		nf.setMinimumIntegerDigits(2);
		nf.setMaximumIntegerDigits(2);

		timeDisplay.setText(nf.format(cal.get(Calendar.HOUR_OF_DAY)) + ":" + nf.format(cal.get(Calendar.MINUTE)) + ":" + nf.format(cal.get(Calendar.SECOND)));
	}

	public void updateOutput(String s) {
		if (s.endsWith("\n"))
			s = s.substring(1, s.length());

		outputScreen.append(s);
		outputScreen.append("\n");
	}

	public void clearOutput() {
		outputScreen.setText("");
	}

	//trunk number 1 - 5 specifies which connections is used
	//phone1 and phone2 are number 1 - 16 specifying phone
	//panel is 400 by 400
	public void showConnection(int trunk, int phone1, int phone2) {
		//variable for main line
		int x1 = 0;
		int x2 = 0;
		int y1 = 0;
		int y2 = 0;

		//variable for back line
		int tempX1 = 0;
		int tempX2 = 0;
		int tempY1 = 0;
		int tempY2 = 0;

		//check for straight line
		if(((phone1 <= 8) && (phone2 > 8)) || ((phone1 > 8) && (phone2 <= 8))) {
			//test if phone1 is smaller
			if(phone1 <= 8) {
				x1 = 0;
				x2 = 400;
				y1 = (50 * phone1) - 25;
				y2 = (50 * (phone2 - 8)) - 25;
				drawMainLine(trunk, x1, y1, x2, y2);
				drawBackLine(trunk,0,0,0,0);
				drawing.repaint();
				return;
			}
			//phone2 the smaller phone
			else {
				x1 = 400;
				x2 = 0;
				y1 = (50 * (phone1 - 8)) - 25;
				y2 = (50 * phone2) - 25;
				drawMainLine(trunk, x1, y1, x2, y2);
				drawBackLine(trunk,0,0,0,0);
				drawing.repaint();
				return;
			}
		}

		//else line curves back
		else {
			//determine if the phones are low or high
			if(phone1 <= 8) {
				x1 = 0;
				x2 = 200;
				y1 = (50 * phone1) - 25;;

				tempX1 = 200;
				tempX2 = 0;
				tempY2 = (50 * phone2) - 25;

				y2 = (Math.abs(y1 - tempY2)/2) + Math.min(y1,tempY2);
				tempY1 = y2;

				drawMainLine(trunk,x1,y1,x2,y2);
				drawBackLine(trunk,tempX1,tempY1,tempX2,tempY2);
				drawing.repaint();
				return;
			}
			//phones are high
			else {
				x1 = 400;
				x2 = 200;
				y1 = (50 * (phone1 - 8)) - 25;

				tempX1 = 200;
				tempX2 = 400;
				tempY2 = (50 * (phone2 - 8)) - 25;

				y2 = (Math.abs(y1 - tempY2)/2) + Math.min(y1,tempY2);
				tempY1 = y2;

				drawMainLine(trunk,x1,y1,x2,y2);
				drawBackLine(trunk,tempX1,tempY1,tempX2,tempY2);
				drawing.repaint();
				return;
			}
		}
	}

	private void drawMainLine(int trunk, int x1, int y1, int x2, int y2) {
		//determine which trunk to draw too
		if(trunk == 1) {
			drawing.setTrunk1(x1,y1,x2,y2);
		}
		else if(trunk == 2) {
			drawing.setTrunk2(x1,y1,x2,y2);
		}
		else if(trunk == 3) {
			drawing.setTrunk3(x1,y1,x2,y2);
		}
		else if(trunk == 4) {
			drawing.setTrunk4(x1,y1,x2,y2);
		}
		else {
			drawing.setTrunk5(x1,y1,x2,y2);
		}

	}

	private void drawBackLine(int trunk, int x1, int y1, int x2, int y2) {
		//determine which trunk to draw too
		if(trunk == 1) {
			drawing.setBackTrunk1(x1,y1,x2,y2);
		}
		else if(trunk == 2) {
			drawing.setBackTrunk2(x1,y1,x2,y2);
		}
		else if(trunk == 3) {
			drawing.setBackTrunk3(x1,y1,x2,y2);
		}
		else if(trunk == 4) {
			drawing.setBackTrunk4(x1,y1,x2,y2);
		}
		else {
			drawing.setBackTrunk5(x1,y1,x2,y2);
		}
	}

	private void launchFrame() {
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.pack();
		frame.setVisible(true);
	}
}